#include "ThreadPool.h"
#include <iostream>

ThreadPool::ThreadPool() {}

bool ThreadPool::checkRunningState() const {
  return this->isPoolRunning_;
};

void ThreadPool::setMode(PoolMode mode) {
  if (checkRunningState()) {
    return;
  }
  this->poolMode_ = mode;
}

void ThreadPool::setTaskQueMaxThreshHold(size_t threshold) {
  if (checkRunningState()) {
    return;
  }

  this->taskQueThreshHold_ = threshold;
}

void ThreadPool::setThreadSizeThreshHold(size_t threshold) {
  if (checkRunningState()) {
    return;
  }
  if (poolMode_ != PoolMode::MODE_CACHED) {
    return;
  }
  this->threadSizeThreshold_ = threshold;
}

// 任务生产者
std::shared_ptr<Result> ThreadPool::submitTask(std::shared_ptr<Task> Tasksptr) {
  // 获取锁
  std::unique_lock<std::mutex> lock(taskQueMtx_);
  // 线程通信
  if (auto flag = notFull_.wait_for(
          lock, std::chrono::seconds(1),
          [&]() { return taskQue_.size() < taskQueThreshHold_; });
      !flag) {
    // 超时仍未满足条件，返回失败
    std::cerr << "task queue is full, submit task fail.\n";
    return Result::make_Result(Tasksptr, false);
  }

  // 队列有空, 任务放入队列
  taskQue_.emplace(Tasksptr);
  taskSize_++;
  // 队列不空了, 通知消费者
  notEmpty_.notify_one();

  if (poolMode_ == PoolMode::MODE_CACHED &&
      this->taskSize_ > this->idleThreadSize_ &&
      this->curThreadSize_ < this->threadSizeThreshold_) { // 达到CACHED模式
    auto ptr = std::make_unique<Thread>(
        [this](int threadId) { threadFunc(threadId); });
    int threadId = ptr->getThreadID();
    threads_.emplace(threadId, std::move(ptr));

    threads_[threadId]->start();

    this->curThreadSize_++;
    this->idleThreadSize_++;
    std::cout << __PRETTY_FUNCTION__ << " tid:" << std::this_thread::get_id() << " CACHED模式" << "\n";
  }

  return Result::make_Result(Tasksptr, true);
};

void ThreadPool::start(size_t initThreadSize) {
  this->isPoolRunning_ = true;

  this->initThreadSize_ = initThreadSize;
  this->curThreadSize_ = initThreadSize;

  for (size_t i = 0; i < initThreadSize_; ++i) {
    auto ptr = std::make_unique<Thread>([this](int threadId) { threadFunc(threadId); });
    int threadId = ptr->getThreadID();
    threads_.emplace(threadId, std::move(ptr));
  }
  for (size_t i = 0; i < initThreadSize_; i++) {
    threads_[i]->start();
    idleThreadSize_++;
  }
}

// 消费者
void ThreadPool::threadFunc(int threadID) {
  auto lasttime = std::chrono::high_resolution_clock().now(); // 上次
  for (;;) {
    std::shared_ptr<Task> task;
    { 
      // 获取锁
      std::unique_lock<std::mutex> lock(taskQueMtx_);
      std::cout << __PRETTY_FUNCTION__ << " tid:" << std::this_thread::get_id() << " 尝试获取任务"<< "\n";

      // cached模式下, 若线程空闲超过一定时间, 则要被回收
      if (this->poolMode_ == PoolMode::MODE_CACHED) {
        // 只有队列为空, 才能notEmpty_.wait_for等待, 若是this->taskQue_.size() > 0则taskQue_.pop(), 所以显示"task queue is full, submit task fail."
        while (this->taskQue_.size() == 0) { 
          if (std::cv_status::timeout == notEmpty_.wait_for(lock, std::chrono::seconds(1))) {  // 区分超时, 还是正在处理任务
            auto now = std::chrono::high_resolution_clock().now(); // 当前
            auto dur = std::chrono::duration_cast<std::chrono::seconds>(
                now - lasttime);
            if (dur.count() >= THREAD_MAX_IDLE_TIME &&
                this->curThreadSize_ > this->initThreadSize_) {
              // 回收线程
              threads_.erase(threadID); // 不使用? std::this_thread::getid();

              curThreadSize_--;
              std::cout << __PRETTY_FUNCTION__ << " tid:" << std::this_thread::get_id() << ", 回收: " << threadID << "\n";
              return;
            }
          }
        }
      } else {
        // 等待notEmpty
        notEmpty_.wait(lock, [&]() { return taskQue_.size() > 0; });
      }

      idleThreadSize_ --;
      
      // 取任务
      task = taskQue_.front();
      taskQue_.pop();
      taskSize_--;

      // 队列还有任务, 通知其他消费者
      if (taskQue_.size() > 0) {
        notEmpty_.notify_all();
      }

      // 通知生产者, 提交任务
      notFull_.notify_all();
    } // 释放锁

    // 线程执行任务
    if (task != nullptr) {
      task->exec();
    }

    lasttime = std::chrono::high_resolution_clock().now();
    idleThreadSize_ ++;
  }
}
